package com.skplanet.oneplusonewindow.moimserver.repository.hibernate;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.SessionFactory;
import org.hibernate.classic.Session;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * {Hibernate}
 *	
 *<p>
 *	기본 기능들인 CRUD 들을 제네릭하게 쓸 수 있는 GenericRepository	
 *
 * @author mook
 *
 *	
 *
 */

public class HibernateGenericRepository<E> implements GenericRepository<E> {

	protected Class<E> entityClass;

	// 현재 Repository 에 접근하는 Domain 클래스 가져오기. 봄싹 소스 참고
	@SuppressWarnings("unchecked")
	public HibernateGenericRepository() {
		ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
		Type type = genericSuperclass.getActualTypeArguments()[0];
		if (type instanceof ParameterizedType) {
			this.entityClass = (Class<E>) ((ParameterizedType) type).getRawType();
		} else {
			this.entityClass = (Class<E>) type;
		}
	}

	@Autowired
	protected SessionFactory sessionFactory;

    protected Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }

    protected Criteria getCriteria() {
        return sessionFactory.getCurrentSession().createCriteria(entityClass);
    }
    
    protected void flushAndClear(){
    	Session session = getCurrentSession();
    	session.flush();
    	session.clear();
    }
    
    /////////////////////////////////////////////////
    // Public Methods
    /////////////////////////////////////////////////
    

    @Override
	public void save(E entity) {
		getCurrentSession().save(entity);
		flushAndClear();
	}


	@SuppressWarnings("unchecked")
	@Override
	public E select(Serializable id){
		return (E) getCurrentSession().get(entityClass, id);
	}
    
	@Override
	public List<E> getAll() {
		Criteria criteria = getCurrentSession().createCriteria(entityClass);
		return criteria.list();
	}

	@Override
	public void delete(E entity){
		getCurrentSession().delete(entity);
		flushAndClear();
	}
	
	@Override
	public void update(E entity){
		getCurrentSession().update( entity );
		flushAndClear();
	}
	
	@Override
	public void flush(){
		getCurrentSession().flush();
	}
	
	@Override
    public void clear() {
        getCurrentSession().clear();
    }

	@SuppressWarnings( "unchecked" )
	@Override
	public E merge(E entity){
		return (E) getCurrentSession().merge(entity);
	}

    @SuppressWarnings("unchecked")
	@Override
	public E findUniqByObject(String columnName, Object object) {
    	Criteria criteria = getCurrentSession().createCriteria(this.entityClass);
    	criteria.add(Restrictions.eq(columnName, object));
		return (E) criteria.uniqueResult();
	}
	
    @Override
	public List<E> findListByObject(String columnName, Object object){
    	Criteria criteria = getCurrentSession().createCriteria(this.entityClass);
    	criteria.add(Restrictions.eq(columnName, object));
		return  criteria.list();
	}

	@Override
	public Object findColumnByObject(String returnColumn, String whereColumn,
			Object whereParameter) {
    	Criteria criteria = getCurrentSession().createCriteria(this.entityClass);
    	criteria.add(Restrictions.eq(whereColumn, whereParameter));
		criteria.setProjection(Projections.property(returnColumn));
		return  criteria.uniqueResult();
	}
	
}
